/**
 * Copyright (C) 2008 Christopher Allen Ogden
 *
 *     This file is part of Odysi.
 *
 *  Odysi is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Odysi is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Odysi.  If not, see <http://www.gnu.org/licenses/>.
 */
#pragma once
#include "singleton.h"
#include "packet.h"
#include "socket.h"
#include "genPackets.h"
#include <boost/shared_array.hpp>

/**
 * Handles incoming and outgoing packets for a connection.
 *
 * @author  Ogden, Chris
 */
class PostService
{
    public:
        /**
         * Constructor.
         *
         * @param sock  The socket to connect to.
         */
        PostService(int sock):_out(NULL),_in(NULL),_outLen(0),_inLen(0),_socket(sock) { }

        /**
         * Set the socket.
         *
         * @param sock  The socket.
         */
        void setSocket(int sock)
        {
            _socket = Socket(sock);
        }

        /**
         * Get the socket.
         *
         * @return  The socket.
         */
        int getSocket(void) const
        {
            return _socket;
        }

        /**
         * Send a packet.
         *
         * @param p The packet.
         */
        void send(const Packet &p)
        {
            const unsigned char *c = reinterpret_cast<const unsigned char *>(p.getData());
            boost::shared_array<unsigned char> buff(new unsigned char[_outLen + p.getLength()]);
            memcpy(buff.get(), _out.get(), _outLen);
            memcpy(buff.get() + _outLen, c, p.getLength());
            _out = buff;
            _outLen += p.getLength();
        }

        /**
         * Receive a packet.
         *
         * @return  A packet.
         */
        Packet recv(void)
        {
            int len = genPacket::getPacketLength(_in.get(), _inLen);
            if (len <= 0) return Packet();
            if (len <= _inLen) {
                Packet p(_in.get(), len);
                boost::shared_array<unsigned char> buff(new unsigned char[_inLen - len]);
                memcpy(buff.get(), _in.get() + len, _inLen - len);
                _in = buff;
                _inLen -= len;
                return p;
            }
            return Packet();
        }

        /**
         * Process.
         */
        void process()
        {
            if (!_socket) return;

            char buff[256];

            // Send data.
            while (_outLen) {
                int len = _outLen;
                if (len > sizeof(buff)) len = sizeof(buff);
                memcpy(buff, _out.get(), len);
                _socket.send(buff, len);
                boost::shared_array<unsigned char> newOut(new unsigned char[_outLen - len]);
                memcpy(newOut.get(), _out.get() + len, _outLen - len);
                _out = newOut;
                _outLen -= len;
            }

            // Receive data.
            int len = 0;
            while ((len = _socket.recv(buff, sizeof(buff))) > 0) {
                boost::shared_array<unsigned char> newIn(new unsigned char[_inLen + len]);
                memcpy(newIn.get(), _in.get(), _inLen);
                memcpy(newIn.get() + _inLen, buff, len);
                _in = newIn;
                _inLen += len;
            }
        }
    private:
        Socket _socket;
        boost::shared_array<unsigned char> _out;
        boost::shared_array<unsigned char> _in;
        unsigned int _outLen;
        unsigned int _inLen;
};
